<?php

class fily_XMLConverter {
    private static $namespaces = array();
    private static $createdObjects = array();

    public static function registerNamespace($namespace, $class) {
        self::$namespaces[strtolower($namespace)]['class'] = $class;
    }

    /**
     *
     * @param <type> $path
     * @return fily_ControlToHtml
     */
    public static function convertFile($path,fily_XMLToControl $base = null) {
        self::$createdObjects = array();
        $xml = simplexml_load_file($path);
        $object =  self::convertXML($xml, $base);
        return $object;
    }

    public static function convertXML(SimpleXMLElement $xml,fily_XMLToControl $base = null ){
       $object =  self::parseXML($xml, null, null);
        if($base!=null){
            // add to the base
            // for correct id generating
            $base->XMLAddControl($object);
        }
        // execute late binding
        foreach (self::$createdObjects as $createdObject) {
            $createdObject->XMLLateBinding($object);
        }
        return $object;
    }


    private static function getNamespaceClass($name) {
        return self::$namespaces[$name]['class'];
    }

    private static function parseXML($xml,$baseNamespace) {
        $object = null;
        $namespace = strtolower($xml->getName());
        $class = self::getNamespaceClass($namespace);
        $innerValue =  $xml->__toString();
        if($class==null) {
            // default
            $object = new fily_ControlContainer($namespace);
        }
        else {
            // create new object
            $object = new $class();
        }
        $attributes = array();
        foreach($xml->attributes() as $key => $value) {
            $attributes[strtolower($key)] = $value->__toString();
        }
        // create attributes
        $object->XMLAttributes($attributes, $innerValue);
        // create functions
        foreach($xml->children('fn', true) as  $function) {
            if($function instanceof SimpleXMLElement) {
                self::parseFunction($function, $object);
            }
        }
        // create childrens
        foreach($xml->children() as  $child) {
            if($child instanceof SimpleXMLElement) {
                $childObject = self::parseXML($child, $namespace);
                if($childObject!=null)
                    $object->XMLAddControl($childObject);
            }
        }
        // add object to created objects
        self::$createdObjects[] = $object;
        return $object;
    }

    private static function parseFunction($xml, $baseObject) {
        $namespace = strtolower($xml->getName());
        $innerValue =  $xml->__toString();
        $parameters = array();
        foreach($xml->attributes() as $key => $value) {
            $parameters[strtolower($key)] = $value;
        }
        // create childrens
        $innerControl= null;
        if(count($xml->children())==1) {
            $innerControl =  self::parseXML($xml->children() , $namespace);
        }
        else if(count($xml->children())>1){
            $innerControl = new fily_ControlList();
            foreach($xml->children() as  $child) {
                if($child instanceof SimpleXMLElement) {
                    $childObject = self::parseXML($child, $namespace);
                    if($childObject!=null)
                        $innerControl->add($childObject);
                }
            }
        }
        $baseObject->XMLCallFunction($namespace, $parameters, $innerValue, $innerControl);
    }

    /**
     * tries to find a control via the find expression
     * it's a help method while ml converting
     * @param <type> $find
     * @param fily_ControlToHtml $control
     * @param fily_ControlToHtml $baseControl
     * @return <type>
     */
    public static function findControl($find,fily_ControlToHtml $control,fily_ControlToHtml $baseControl){
        $returnControl = null;
        if(strncmp($find, "sid:", 4) == 0){
            $find = str_replace("sid:", "", $find);
             $returnControl = $baseControl->getControlBySid($find);
        }
        else if(fily_ExpressionHelper::isExpression($find)){
               $returnControl = $control->find($find);
        }
        else{
               $returnControl = $baseControl->getControlById($find);
        }
        return $returnControl;
    }
}
?>